package com.xyzwps.server.paimon.model.repository

import com.xyzwps.server.paimon.model.entity.Article
import com.xyzwps.server.paimon.model.table.ArticleTable
import com.xyzwps.server.paimon.value.UserId
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.SortOrder
import org.jetbrains.exposed.v1.core.and
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.core.less
import org.jetbrains.exposed.v1.jdbc.insertAndGetId
import org.jetbrains.exposed.v1.jdbc.selectAll
import org.jetbrains.exposed.v1.jdbc.update
import org.springframework.stereotype.Repository

internal val a = ArticleTable

fun rowToArticle(it: ResultRow): Article = Article(
    id = it[a.id].value,
    uid = it[a.uid],
    userId = UserId(it[a.userId]),
    title = it[a.title],
    content = it[a.content],
    createdAt = it[a.createdAt]
)

@Repository
class ArticleRepository() {

    // TODO: upsert
    fun save(article: Article): Article {
        if (article.id != null) {
            ArticleTable.update({ a.id eq article.id }) {
                it[uid] = article.uid
                it[userId] = article.userId.value
                it[title] = article.title
                it[content] = article.content
                it[createdAt] = article.createdAt
            }
            return article
        }
        val id = ArticleTable.insertAndGetId {
            it[uid] = article.uid
            it[userId] = article.userId.value
            it[title] = article.title
            it[content] = article.content
            it[createdAt] = article.createdAt
        }
        return article.copy(id = id.value)
    }

    fun findByUidAndUserId(uid: String, userId: UserId): Article? =
        ArticleTable.selectAll()
            .where { (a.uid eq uid) and (a.userId eq userId.value) }
            .map(::rowToArticle)
            .firstOrNull()

    fun findByUid(uid: String): Article? =
        ArticleTable.selectAll()
            .where { a.uid eq uid }
            .map(::rowToArticle)
            .firstOrNull()

    fun findByUserIdOrderByIdDesc(userId: UserId, limit: Int): List<Article> =
        ArticleTable.selectAll()
            .where { a.userId eq userId.value }
            .orderBy(a.id, SortOrder.DESC)
            .limit(limit)
            .map(::rowToArticle)
            .toList()

    fun findByUserIdAndIdLessThanOrderByIdDesc(userId: UserId, beforeId: Long, limit: Int): List<Article> =
        ArticleTable.selectAll()
            .where { (a.userId eq userId.value) and (a.id less beforeId) }
            .orderBy(a.id, SortOrder.DESC)
            .limit(limit)
            .map(::rowToArticle)
            .toList()
}

